// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Sdk.Interception;

namespace TestValidationAspects.Sdk.Interception
{
	[TestFixture]
	public class TestGetInterceptionValidationProperties
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_ForType_throws_for_null_Type_param()
		{
			GetInterceptionValidationProperties.ForType(null, false).Count();
		}

		[Test]
		public void Test_ForType_throws_for_decorated_non_setter_property()
		{
			PropertyInfo propertyInfo = TypeOf<DecoratedNonSetterProperty>.GetProperty(x => x.NoSetter);

			Test.Throws<ValidationException>(() => GetInterceptionValidationProperties.ForType(typeof(DecoratedNonSetterProperty), false).Count(),
			                                 string.Format("Validation cannot be applied to property [name:{0}] [type:{1}]. Property does not define a set method.", propertyInfo.Name,
			                                               propertyInfo.DeclaringType));
		}

		[Test]
		public void Test_ForType_returns_only_decorated_properties()
		{
			var properties = GetInterceptionValidationProperties.ForType(typeof(Dummy), true);

			Assert.AreEqual(1, properties.Count());
			Assert.IsTrue(properties.Contains(TypeOf<Dummy>.GetProperty(x => x.DecoratedProperty)));
		}

		[Test]
		public void Test_ForType_returns_all_properties()
		{
			var properties = GetInterceptionValidationProperties.ForType(typeof(Dummy), false);

			Assert.AreEqual(3, properties.Count());
			Assert.IsTrue(properties.Contains(TypeOf<Dummy>.GetProperty(x => x.DecoratedProperty)));
			Assert.IsTrue(properties.Contains(TypeOf<Dummy>.GetProperty(x => x.NonDecoratedProperty)));
			Assert.IsTrue(properties.Contains(typeof(Dummy).GetProperty("StaticProperty")));
		}

		#region Mocks
		public class Dummy
		{
			[NotNull]
			public string DecoratedProperty { get; set; }

			public string NonDecoratedProperty { get; set; }

			public string NoSetter
			{
				get { return "test"; }
			}

			public static string StaticProperty { get; set; }
		}

		public class DecoratedNonSetterProperty
		{
			[NotNullOrEmpty]
			public string NoSetter
			{
				get { return "test"; }
			}
		}
		#endregion
	}
}